/**
  ******************************************************************************
  * @file    flash.c
  * @author  GEEKROS,  site:www.geekros.com
  ******************************************************************************
*/

#include "flash.h"

//定义最小地址
#define Flash_Min_Addr 0X08040000
//定义最大地址
#define Flash_Max_Addr 0x081FFFFF
/******************************************************************
  * @ 函数名  ： Flash_Read_Word
  * @ 功能说明： 读取指定地址的半字(16位数据)
  * @ 参数    ： NULL 
  * @ 返回值  ： NULL
  *****************************************************************/
u32 Flash_Read_Word(u32 faddr)
{
	return *(vu32*)faddr;
}

/******************************************************************
  * @ 函数名  ： Flash_Get_Sector
  * @ 功能说明： 获取某个地址所在的flash扇区
  * @ 参数    ： NULL 
  * @ 返回值  ： NULL
  *****************************************************************/
uint16_t Flash_Get_Sector(u32 addr)
{
	if((addr < ADDR_FLASH_SECTOR_1) && (addr >= ADDR_FLASH_SECTOR_0))
	{
		return FLASH_Sector_0;
	}else if((addr < ADDR_FLASH_SECTOR_2) && (addr >= ADDR_FLASH_SECTOR_1)){
		return FLASH_Sector_1;
	}else if((addr < ADDR_FLASH_SECTOR_3) && (addr >= ADDR_FLASH_SECTOR_2)){
		return FLASH_Sector_2;
	}else if((addr < ADDR_FLASH_SECTOR_4) && (addr >= ADDR_FLASH_SECTOR_3)){
		return FLASH_Sector_3;
	}else if((addr < ADDR_FLASH_SECTOR_5) && (addr >= ADDR_FLASH_SECTOR_4)){
		return FLASH_Sector_4;
	}else if((addr < ADDR_FLASH_SECTOR_6) && (addr >= ADDR_FLASH_SECTOR_5)){
		return FLASH_Sector_5;
	}else if((addr < ADDR_FLASH_SECTOR_7) && (addr >= ADDR_FLASH_SECTOR_6)){
		return FLASH_Sector_6;
	}else if((addr < ADDR_FLASH_SECTOR_8) && (addr >= ADDR_FLASH_SECTOR_7)){
		return FLASH_Sector_7;
	}else if((addr < ADDR_FLASH_SECTOR_9) && (addr >= ADDR_FLASH_SECTOR_8)){
		return FLASH_Sector_8;
	}else if((addr < ADDR_FLASH_SECTOR_10) && (addr >= ADDR_FLASH_SECTOR_9)){
		return FLASH_Sector_9;
	}else if((addr < ADDR_FLASH_SECTOR_11) && (addr >= ADDR_FLASH_SECTOR_10)){
		return FLASH_Sector_10;
	}else if((addr < ADDR_FLASH_SECTOR_12) && (addr >= ADDR_FLASH_SECTOR_11)){
		return FLASH_Sector_11;
	}else if((addr < ADDR_FLASH_SECTOR_13) && (addr >= ADDR_FLASH_SECTOR_12)){
		return FLASH_Sector_12;
	}else if((addr < ADDR_FLASH_SECTOR_14) && (addr >= ADDR_FLASH_SECTOR_13)){
		return FLASH_Sector_13;
	}else if((addr < ADDR_FLASH_SECTOR_15) && (addr >= ADDR_FLASH_SECTOR_14)){
		return FLASH_Sector_14;
	}else if((addr < ADDR_FLASH_SECTOR_16) && (addr >= ADDR_FLASH_SECTOR_15)){
		return FLASH_Sector_15;
	}else if((addr < ADDR_FLASH_SECTOR_17) && (addr >= ADDR_FLASH_SECTOR_16)){
		return FLASH_Sector_16;
	}else if((addr < ADDR_FLASH_SECTOR_18) && (addr >= ADDR_FLASH_SECTOR_17)){
		return FLASH_Sector_17;
	}else if((addr < ADDR_FLASH_SECTOR_19) && (addr >= ADDR_FLASH_SECTOR_18)){
		return FLASH_Sector_18;
	}else if((addr < ADDR_FLASH_SECTOR_20) && (addr >= ADDR_FLASH_SECTOR_19)){
		return FLASH_Sector_19;
	}else if((addr < ADDR_FLASH_SECTOR_21) && (addr >= ADDR_FLASH_SECTOR_20)){
		return FLASH_Sector_20;
	}else if((addr < ADDR_FLASH_SECTOR_22) && (addr >= ADDR_FLASH_SECTOR_21)){
		return FLASH_Sector_21;
	}else if((addr < ADDR_FLASH_SECTOR_23) && (addr >= ADDR_FLASH_SECTOR_22)){
		return FLASH_Sector_22;
	}else
		return FLASH_Sector_23;
}

/*
擦除扇区函数 擦除都是以一个扇区作为单位的 每次擦除一个扇区  读取可以不用读整个扇区，
只需要读需要数据的扇区即可
参数：Strat_Sector 起始扇区 End_Sector 终始扇区
*/
/******************************************************************
  * @ 函数名  ： ERASE_Sector
  * @ 功能说明： 擦除所在扇区数据，这里的扇区是号，并不是单位地址
  * @ 参数    ： NULL 
  * @ 返回值  ： NULL
  ***************************************u**************************/
static int Flash_ERASE_Sector(u32 Strat_Sector,u32 End_Sector)
{
	//要擦除的起始扇区(包含)及结束扇区(不包含)，如8-12，表示擦除8、9、10、11号扇区
	u32 uwStartSector = 0;	 //开始扇区
	u32 uwEndSector = 0;	 //结束扇区
	u32 uwSectorCounter = 0;//擦除的扇区
	
  	//FLASH 解锁，使能访问FLASH控制寄存器
  	FLASH_Unlock();
    FLASH_DataCacheCmd(DISABLE); //FLASH擦除期间，必须禁止数据缓存
  	//擦除用户区域 (用户区域指程序本身没有使用的空间，可以自定义)，清除各种FLASH的标志位 
 	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
	uwStartSector = Flash_Get_Sector(Strat_Sector);		//开始的扇区地址
	uwEndSector = Flash_Get_Sector(End_Sector);			//结束的扇区地址
	FLASH_Unlock();
  	/* 开始擦除操作 */
	uwSectorCounter = uwStartSector;					//获取当前擦除地址值
	while (uwSectorCounter <= uwEndSector) 				//进行扇区擦除
	{
		/* VoltageRange_3 以“字”的大小进行操作 */ 
		if(FLASH_EraseSector(uwSectorCounter, VoltageRange_3) != FLASH_COMPLETE)
		{ 
			//擦除失败返回-1		
			return -1;	
		}
		  
		if (uwSectorCounter == FLASH_Sector_11)
		{
			//如果地址需要变成扇区12，扇区11和扇区12之间隔了40个号
			uwSectorCounter += 40;
		} 
		else 
		{
			//如果不是，就正常扇区之间间隔8个号
			uwSectorCounter += 8;		
		}
	}
	
	return 1;
}

/******************************************************************
  * @ 函数名  ： Flash_Write
  * @ 功能说明： 写入FLASH数据
  * @ 参数    ： NULL 
  * @ 返回值  ： NULL
  *****************************************************************/
u32 Flash_Write(u32 Start_Address,u8* Data_Buf,u32 Data_Len)
{
	u32 Start_Add,End_Add,Now_Add;//定义初始地址,结束地址
	u32 Real_End_Data;
	u8 Now_Data;//定义获取数据数据
	Start_Add = Start_Address;
	End_Add = Start_Address + 1*Data_Len;//由于输入的是1个字节的内容，所以结束地址的偏移量为字节长度*1
	Real_End_Data = Start_Address + (Data_Len/4 + 1)*4;
	Now_Add = Start_Add;
	LOS_IntLock();//关闭cpu中断
	if(Flash_ERASE_Sector(Start_Add,Real_End_Data) != 1)//清空地址所在扇区
	{
		
		return -1;
	}
	
	while(Now_Add <= End_Add)
	{
		//获取当前字节数据
		Now_Data = *Data_Buf;
		if (FLASH_ProgramByte(Now_Add, Now_Data) == FLASH_COMPLETE)		//写入成功
		{
			Now_Add = Now_Add + 1;		//进入下个字的头地址  要是半个字 +2 一个字节+1
			Data_Buf++;					//移动到下一个数据
		}
		else
		{ 
			//如果写入失败
			return -1;		
		}	
	}
	while(Real_End_Data < End_Add)
	{
		if (FLASH_ProgramByte(Now_Add, (u32)NULL) == FLASH_COMPLETE)		//写入成功
		{
			Now_Add = Now_Add + 1;		//进入下个字的头地址  要是半个字 +2 一个字节+1
		}
		else
		{ 
			//如果写入失败
			return -1;		
		}
	}
	//给flash上锁，防止内容篡改
	FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束，开启数据缓存
	FLASH_Lock(); 
	LOS_IntUnLock();//打开cpu中断
	return 1;
}

/******************************************************************
  * @ 函数名  ： Flash_Read
  * @ 功能说明： 读取FLASH数据
  * @ 参数    ： NULL 
  * @ 返回值  ： NULL
  *****************************************************************/
void Flash_Read(u32 Start_Address,u8* Data_Buf,u32 Data_Len)
{
	u32 Start_Add,End_Add,Now_Add;//定义初始地址,结束地址
	u8 Now_Data;//定义获取数据数据
	u32 num = 0;
	Start_Add = Start_Address;
	End_Add = Start_Address + 1*Data_Len;//由于输入的是1个字节的内容，所以结束地址的偏移量为字节长度*1
	Now_Add = Start_Add;
	while(Now_Add < End_Add)
	{
		Data_Buf[num++] = *(__IO u8*)Now_Add;
		Now_Add = Now_Add + 1;//每次读取一个字节，地址加1
	}	
}

/******************************************************************
  * @ 函数名  ： Flash_Get_0x
  * @ 功能说明： Flash回调函数
  * @ 参数    ： char* Data 数据 
  * @ 返回值  ： NULL
  *****************************************************************/
u32 Flash_Get_0x(char* Data)
{
	u32 Get_Data = 0;
	if((Data[0] == '0') && (Data[1] == 'x'))
	{
		for(int k = 2;k < 10;k++)
		{
			if((Data[k] >= 0x30) && (Data[k] <= 0x39))
			{
				Get_Data += (Data[k] - 0x30)*pow(16,9-k);
			}
			else if((Data[k] >= 0x41) && (Data[k] <= 0x46))
			{
				Get_Data += (Data[k] - 0x41 + 10)*pow(16,9-k);
			}
			else if((Data[k] >= 0x61) && (Data[k] <= 0x66))
			{
				Get_Data += (Data[k] - 0x61 + 10)*pow(16,9-k);
			}
		}
	}
	return Get_Data;
}

/******************************************************************
  * @ 函数名  ： Flash_Callback
  * @ 功能说明： Flash回调函数
  * @ 参数    ： char *type 类型 
  * @ 参数    ： u32 Start_Address 写入地址
  * @ 参数    ： u8* Data_Buf 写入数据串
  * @ 参数    ： u32 Data_Len 数据长度
  * @ 返回值  ： NULL
  *****************************************************************/
void Flash_Callback(char *type,char *Start_Address,u8* Data_Buf,u32 Data_Len)
{
	u32 Get_Start_Addr;
	Get_Start_Addr = Flash_Get_0x(Start_Address);
	if(memcmp(type, "flash_write", 11) == 0)
	{
		if((Get_Start_Addr < Flash_Min_Addr) || (Get_Start_Addr > Flash_Max_Addr))
		{
			Usb_Write_Data("Address Must Set Between %#f And %#f!! \r\n Your Addr Set Is:%x \r\n",Flash_Min_Addr,Flash_Max_Addr,Get_Start_Addr);
		}
		else
		{
			if(Flash_Write(Get_Start_Addr,Data_Buf,Data_Len) == 1)
			{
				Usb_Write_Data("{\"type\":\"flash_write\",\"Start_Address\":\"%#x\",\"Data_Buf\":\"%s\",\"Data_Len\":\"%d\"}\r\n",Get_Start_Addr,Data_Buf,Data_Len);
			}
		}		
	}
	else if(memcmp(type, "flash_read", 10) == 0)
	{
		u32 Data_mal_Len;
		if(Data_Len%4 == 0)
			Data_mal_Len = Data_Len/4;
		else
			Data_mal_Len = Data_Len/4+1;

		u8* Get_Flash_Buff;
		Get_Flash_Buff = (u8*)malloc(Data_mal_Len+1);
		if((Get_Start_Addr < Flash_Min_Addr) || (Get_Start_Addr > Flash_Max_Addr))
		{
			Usb_Write_Data("Address Must Set Between %#f And %#f!! \r\n Your Addr Set Is:%x \r\n",Flash_Min_Addr,Flash_Max_Addr,Get_Start_Addr);
		}
		else
		{
			Flash_Read(Get_Start_Addr,Get_Flash_Buff,Data_Len);
			Get_Flash_Buff[Data_Len] = '\0';
			for(int kk = Data_Len+1;kk <= Data_mal_Len*4+4;kk++)
			{
				Get_Flash_Buff[kk] = (u8)NULL;
			}
			Usb_Write_Data("{\"type\":\"flash_read\",\"Start_Address\":\"%#x\",\"Buff\":\"%s\",\"Data_Len\":\"%d\"}\r\n",Get_Start_Addr,Get_Flash_Buff,Data_Len);
		}
		free(Get_Flash_Buff);
	}
}

